package cn.tedu.eb_film.service.impl;

import cn.tedu.eb_film.ex.ServiceException;
import cn.tedu.eb_film.mapper.MovieMapper;
import cn.tedu.eb_film.mapper.MovieTypeMapper;
import cn.tedu.eb_film.pojo.dto.MovieAddNewDTO;
import cn.tedu.eb_film.pojo.dto.MovieExcelDTO;
import cn.tedu.eb_film.pojo.dto.MovieUpdateDTO;
import cn.tedu.eb_film.pojo.entity.Movie;
import cn.tedu.eb_film.pojo.vo.MovieListVO;
import cn.tedu.eb_film.pojo.vo.MovieStandardVO;
import cn.tedu.eb_film.pojo.vo.MovieTypeStandardVO;
import cn.tedu.eb_film.redis.IMovieRedisRepository;
import cn.tedu.eb_film.service.MovieService;
import cn.tedu.eb_film.utils.JsonPage;
import cn.tedu.eb_film.utils.ServiceCode;
import cn.tedu.eb_film.utils.StateCode;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 电影表(movie)的实现类
 *
 * @author diaojie
 * @since 2023/03/17 13:20:47
 */
@Slf4j
@Service
public class MovieServiceImpl implements MovieService {
    
    @Autowired
    private MovieMapper movieMapper;

    @Autowired
    private MovieTypeMapper movieTypeMapper;

    @Autowired
    private IMovieRedisRepository movieRedisRepository;
    @Override
    public void rebuildCache(){
        log.debug("开始处理[电影数据的缓存预热]的业务");
        // 删除缓存中的电影列表
        movieRedisRepository.deleteList();
        // 从数据库中查询所有电影的列表
        List<MovieListVO> list = movieMapper.listReleaseDate();
        // 将电影列表写入到缓存中
        movieRedisRepository.save(list);
        // 删除缓存中所有的电影的数据项
        movieRedisRepository.deleteAllItem();
        // 遍历电影列表的数据
        for (MovieListVO movieListVO : list) {
            // 获取每个电影数据的ID，并根据此ID从数据库中查询电影的详情
            MovieStandardVO movieStandardVO =
                    movieMapper.getStandardById(movieListVO.getId());
            // 将每一个电影详情写入到缓存中
            movieRedisRepository.save(movieStandardVO);
        }
    }


    @Override
    public void addNew(MovieAddNewDTO movieAddNewDTO) {
        log.debug("开始处理【添加电影】的业务,movieAddNewDTO:{}",movieAddNewDTO);
        //获取电影名称并判断与数据库中的电影名称是否一致

        int count = movieMapper.countByName(movieAddNewDTO.getZnName());

        if (count == 1){
            //是
            String message ="添加电影失败，电影名已存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        ///创建实体类Movie
        Movie movie = new Movie();
        //将movieAddNewDTO复制给movie
        BeanUtils.copyProperties(movieAddNewDTO, movie);

        String type = Arrays.toString(movieAddNewDTO.getType());
        type = type.substring(1, type.length() - 1);
        movie.setType(type);

        //设置对应初始值
        movie.setBoxOffice(0L);
        movie.setScore(BigDecimal.valueOf(0.0));
        movie.setNumberWantToSee(0L);
        movie.setNumberViewers(0L);
        movie.setCollectUserCount(0L);
        movie.setCommentCount(0L);

        //添加创建,更新时间
        LocalDateTime localDateTime = LocalDateTime.now();
        movie.setCreateTime(localDateTime);
        movie.setUpdateTime(localDateTime);

        //添加到数据库
        int row = movieMapper.insert(movie);
        if (row != 1){
            String message ="添加电影失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addExcelList(List<MovieExcelDTO> list) {
        log.debug("开始处理【批量添加电影】的业务,movieAddNewDTO:{}",list);
        //创建movieList集合
        List<Movie> movieList = new ArrayList<>();
        for (MovieExcelDTO movieExcelDTO : list) {
            int count = movieMapper.countByName(movieExcelDTO.getZnName());
            if (count == 1){
                //是
                String message ="添加电影失败，电影名已存在";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
            }
            ///创建实体类Movie
            Movie movie = new Movie();
            //将movieExcelDTO复制给movie
            BeanUtils.copyProperties(movieExcelDTO, movie);
            //设置对应初始值
            movie.setBoxOffice(0L);
            movie.setScore(BigDecimal.valueOf(0.0));
            movie.setNumberWantToSee(0L);
            movie.setNumberViewers(0L);
            movie.setCollectUserCount(0L);
            movie.setCommentCount(0L);

            //添加创建,更新时间
            LocalDateTime localDateTime = LocalDateTime.now();
            movie.setCreateTime(localDateTime);
            movie.setUpdateTime(localDateTime);
            movieList.add(movie);
            }
        log.debug("开始处理【批量添加电影】的业务,movieList:{}",movieList);
        //添加到数据库
        int row = movieMapper.insertBatch(movieList);
        if (row != movieList.size()){
            String message ="批量添加电影失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
    }


    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【删除电影】的业务,id:{}",id);
        //判断删除的id是否存在
        MovieStandardVO movie = movieMapper.getStandardById(id);
        if (movie == null){
            //为空
            String message ="删除电影失败，电影名不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }
        int row = movieMapper.deleteById(id);
        if (row != 1){
            String message ="删除电影失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE,message);
        }

    }

    @Override
    public void deleteByIds(Long[] ids) {
        log.debug("开始处理【批量删除电影】的业务,ids:{}", Arrays.toString(ids));
        int rows = movieMapper.deleteByIds(ids);
        if (rows != 1){
            String message ="批量删除电影失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE,message);
        }

    }

    @Override
    public void updateInfoId(Long id, MovieUpdateDTO movieUpdateDTO) {
        log.debug("开始处理【修改电影数据】的业务，id：{}，movieUpdateDTO:{}",id,movieUpdateDTO);
        //调用movieMapper对象的getStandardId()方法查询
        MovieStandardVO queryResult = movieMapper.getStandardById(id);
        //判断是否为空
        if (queryResult == null){
            //为空
            String message ="修改电影详情失败，该电影不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }

        //调用movieMapper对象的countByNameAndNotId()方法
        int count = movieMapper.countByNameAndNotId(id, movieUpdateDTO.getZnName());
        if (count != 0){
            //不为0，则名称重复
            String message = "修改电影详情失败，电影名称已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        //创建实体类movie
        Movie movie = new Movie();
        //将movieUpdateDTO复制给movie
        BeanUtils.copyProperties(movieUpdateDTO,movie);
        movie.setId(id);
        String type = Arrays.toString(movieUpdateDTO.getType());
        type = type.substring(1, type.length() - 1);
        movie.setType(type);
        //修改电影数据
        int row = movieMapper.update(movie);
        if (row != 1){
            String message ="修改电影失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE,message);
        }
    }

    @Override
    public void setEnable(Long id) {
        log.debug("开始处理【启用电影】的业务，参数：{}", id);
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        log.debug("开始处理【禁用电影】的业务，参数：{}", id);
        updateEnableById(id, 0);
    }

    private void updateEnableById(Long id, Integer enable) {
        // 调用Mapper对象的getStandardById()方法执行查询
        MovieStandardVO currentMovie = movieMapper.getStandardById(id);
        // 判断查询结果是否为null，如果是，则抛出异常
        if (currentMovie == null) {
            String message = ENABLE_TEXT[enable] + "电影失败，电影数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }

        // 判断查询结果中的enable与参数enable是否相同，如果是，则抛出异常（当前状态与目标状态相同，没必要执行更新）
        if (currentMovie.getState().equals(enable)) {
            String message = ENABLE_TEXT[enable] + "电影失败，此电影已经处于" + ENABLE_TEXT[enable] + "状态！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }

        // 创建Movie对象
        Movie updateMovie = new Movie();
        // 向Category对象中封装属性值：id, enable，均来自方法参数
        updateMovie.setId(id);
        updateMovie.setState(enable);
        // 调用Mapper对象的update()方法执行更新
        int rows = movieMapper.update(updateMovie);
        if (rows != 1) {
            String message = ENABLE_TEXT[enable] + "电影失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE, message);
        }
    }


    @Override
    public MovieStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据id查询电影数据】的业务，id：{}",id);
        MovieStandardVO movie = movieRedisRepository.get(id);
        if (movie == null){
            String message ="查询电影详情失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }
        MovieStandardVO movieStandardVO = movieTypeByMovieId(movie);

        return movieStandardVO;
    }

    @Override
    public List<MovieListVO> listReleaseDate() {
        log.debug("开始处理【按照时间前后查询电影】的业务,无参数");
        List<MovieListVO> releaseDate = movieRedisRepository.list();
        List<MovieListVO> list = movieType(releaseDate);
        return list;
    }

    @Override
    public List<MovieListVO> listComeSoonAll() {
        log.debug("即将处理【即将上映的电影】功能");
        List<MovieListVO> movieList = movieMapper.listComeSoonAll();
        List<MovieListVO> list = movieType(movieList);
        return list;
    }

    @Override
    public List<MovieListVO> listRelease() {
        log.debug("即将处理【正在上映的电影】功能");
        List<MovieListVO> movieList = movieMapper.listRelease();
        List<MovieListVO> list = movieType(movieList);
        return list;
    }

    @Override
    public Long listReleaseDateCount() {
        log.debug("查询上映的总数量");
        return movieRedisRepository.countRelease();
    }

    @Override
    public List<MovieListVO> listReleasePage(Long start, Long end) {
        log.debug("分页查询正在上映的电影");
        return movieRedisRepository.listPage(start,end);
    }

    @Override
    public JsonPage<MovieListVO> listTop(String znName, Integer page, Integer pageSize) {
        log.debug("开始处理【按照电影名称查询电影】的业务,znName:{},page:{},size:{}", znName, page, pageSize);
        log.debug("开始处理【按照搜索查询电影】的业务,znName:{}", znName);
        if(znName=="" || znName==null){
            String message = "请输入电影名称";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }

        PageHelper.startPage(page,pageSize);

        List<MovieListVO> list = movieMapper.listTop(znName);
        if (list.size() == 0){
            String message = "查询电影不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);

        }
        return JsonPage.restPage(new PageInfo<>(list));
    }

    @Override
    public List<MovieListVO> listComeSoon(String type, String country, String releaseDate) {
        log.debug("开始处理【按照即将上映时间查询电影】的业务,type:{},country:{},releaseDate:{}",type,country,releaseDate);
        return movieMapper.listComeSoon(type,country,releaseDate);
    }

    @Override
    public List<MovieListVO> listSearch( String znName,String type, String country, String releaseDate) {
        log.debug("开始处理【按照搜索查询电影】的业务,type:{},country:{},releaseDate:{}",type,country,releaseDate);
        List<MovieListVO> listSearch = movieMapper.listSearch(znName, type, country, releaseDate);
        //调用movieType（）方法获取电影类型名称
        List<MovieListVO> list = movieType(listSearch);
        if (list.size() == 0){
            String message = "没有找到匹配的电影名称";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        return list;
    }

    /**
     * 根据电影名称模糊查询
     * @param znName
     * @return
     */
    @Override
    public List<MovieListVO> searchMovie(String znName) {
        log.debug("开始处理【按照搜索查询电影】的业务,znName:{}", znName);
        if(znName=="" || znName==null){
            String message = "请输入电影名称";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        List<MovieListVO> listSearch = movieMapper.SearchMovie(znName);
        List<MovieListVO> list = movieType(listSearch);
        if (list.size() == 0){
            String message = "查询电影不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);

        }
        return list;
    }
    @Override
    public List<MovieListVO> listNumberWantToSee() {
        log.debug("开始处理【按照想看人数查询电影】的业务,无参数");
        List<MovieListVO>  listNumberWantToSee= movieMapper.listNumberWantToSee();
        //调用movieType（）方法获取电影类型名称
        List<MovieListVO> list = movieType(listNumberWantToSee);
        return list;
    }

    @Override
    public List<MovieListVO> listScore() {
        log.debug("开始处理【按照评分高低查询电影】的业务,无参数");
        List<MovieListVO> listScore = movieMapper.listScore();
        //调用movieType（）方法获取电影类型名称
        List<MovieListVO> list = movieType(listScore);
        return list;
    }

    @Override
    public List<MovieListVO> listBoxOffice() {
        log.debug("开始处理【按照票房高低查询电影】的业务,无参数");
        List<MovieListVO> listBoxOffice = movieMapper.listBoxOffice();
        //调用movieType（）方法获取电影类型名称
        List<MovieListVO> list = movieType(listBoxOffice);
        return list;

    }

    // 分页查询所有电影信息的方法
    // page是页码,pageSize每页条数
    @Override
    public JsonPage<MovieListVO> getAllMovieByPage(Integer page, Integer pageSize) {
        // PageHelper框架实现分页的方法,就是在执行查询前来设置分页条件
        // 在查询执行之前,使用PageHelper.startPage设置要查询的页码和每页条数
        // 这里的page从1开始,既page是1,查询的就是第一页
        PageHelper.startPage(page,pageSize);
        // 在上面设置好分页条件后,下面执行的查询操作,就会在sql末尾自动添加limit限制查询范围
        List<MovieListVO> movieList = movieMapper.listReleaseDate();
        //查询电影类型的名字
        List<MovieListVO> list = movieType(movieList);
        // 查询结果list只包含分页数据,并不包含分页信息(总页数,总条数等)
        // 所以业务逻辑层使用PageInfo类型作为返回值,它既能包含分页数据,又能包含分页信息
        // 和SpringData中的Page类功能类似
        // 使用它的方法就是直接实例化PageInfo对象,该类在构造方法中会自动计算分页信息
        // 构造方法参数传入list,就是给分页数据赋值
        return JsonPage.restPage(new PageInfo<>(list));
    }

    /**
     * 该方法通过电影表中type的id,查找到电影的类型
     * @param movieList 传入电影列表
     * @return 电影表的数据
     */
    public List<MovieListVO> movieType( List<MovieListVO> movieList){
        //创建list对象
        List<MovieListVO> list = new ArrayList<>();
        movieList.forEach(movie -> {
            //创建movieListVO对象
            MovieListVO movieListVO = new MovieListVO();
            //将每个遍历对象的值赋值给movieListVO
            BeanUtils.copyProperties(movie, movieListVO);
            //获取电影表的类型
            String typeStr = movie.getType();
            //typeStr="1,2,3"通过”,“将数据分开，组成数组[1,2,3]
            String[] newTypeStr = typeStr.split(",");
            //创建 stringBuilder对象
            StringBuilder stringBuilder = new StringBuilder();
            //遍历newTypeStr数组
            for (String typeId : newTypeStr) {
                //将typeId前后去空，并将String转为Integer
                Integer index = Integer.valueOf(typeId.trim());
                //调用movieTypeMapper.getStandardById()获取电影类型数据
                MovieTypeStandardVO movieType =
                        movieTypeMapper.getStandardById(index);
                //如果movieType为空，或者不存在就跳过
                if (movieType == null ||
                        StateCode.STATE_DELETE.getValue().equals(movieType.getState())) {
                    continue;
                }
                //将电影类型添加到stringBuilder中
                stringBuilder.append(movieType.getName()).append(",");
            }
            //转化为String类型
            String typeString = stringBuilder.toString();

            //去除到最后一个”,“
            typeString = typeString.substring(0, typeString.lastIndexOf(","));
            //将查询并转换好的类型重新设置到movieListVO
            movieListVO.setType(typeString);
            //将movieListVO添加到list里
            list.add(movieListVO);
        });
        return list;
    }

    /**
     * 该方法通过电影表中type的id,查找到电影的类型
     * @param movie 传入电影数据
     * @return 电影表的数据
     */
    public MovieStandardVO movieTypeByMovieId( MovieStandardVO movie){

            //获取电影表的类型
            String typeStr = movie.getType();
            //typeStr="1,2,3"通过”,“将数据分开，组成数组[1,2,3]
            String[] newTypeStr = typeStr.split(",");
            //创建 stringBuilder对象
            StringBuilder stringBuilder = new StringBuilder();
            //遍历newTypeStr数组
            for (String typeId : newTypeStr) {
                //将typeId前后去空，并将String转为Integer
                Integer index = Integer.valueOf(typeId.trim());
                //调用movieTypeMapper.getStandardById()获取电影类型数据
                MovieTypeStandardVO movieType =
                        movieTypeMapper.getStandardById(index);
                //如果movieType为空，或者不存在就跳过
                if (movieType == null ||
                        StateCode.STATE_DELETE.getValue().equals(movieType.getState())) {
                    continue;
                }
                //将电影类型添加到stringBuilder中
                stringBuilder.append(movieType.getName()).append(",");
            }
            //转化为String类型
            String typeString = stringBuilder.toString();

            //去除到最后一个”,“
            typeString = typeString.substring(0, typeString.lastIndexOf(","));
            //将查询并转换好的类型重新设置到movie
            movie.setType(typeString);

        return movie;
    }



}
